using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Numerics;

namespace Sunny.UI;

public static class MathEx
{
	public enum Characters
	{
		[DisplayText("01")]
		BINARY,
		[DisplayText("0123")]
		QUATERNARY,
		[DisplayText("012345")]
		SEPTENARY,
		[DisplayText("01234567")]
		OCTAL,
		[DisplayText("0123456789")]
		DECIMAL,
		[DisplayText("0123456789MN")]
		DUODECIMAL,
		[DisplayText("0123456789ABCDEF")]
		HEX
	}

	public const string CHARS_BINARY = "01";

	public const string CHARS_QUATERNARY = "0123";

	public const string CHARS_SEPTENARY = "012345";

	public const string CHARS_OCTAL = "01234567";

	public const string CHARS_DECIMAL = "0123456789";

	public const string CHARS_DUODECIMAL = "0123456789MN";

	public const string CHARS_HEX = "0123456789ABCDEF";

	public const string CHARS_PUREUPPERCHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

	public const string CHARS_PURECHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

	public const string CHARS_36 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

	public const string CHARS_62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

	public const string CHARS_32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";

	public static int Get2PowNHigh(int value)
	{
		value--;
		value |= value >> 1;
		value |= value >> 2;
		value |= value >> 4;
		value |= value >> 8;
		value |= value >> 16;
		return ++value;
	}

	public static int Get2PowNLow(int value)
	{
		return Get2PowNHigh(value) >> 1;
	}

	public static int BinarySearchNearIndex<T>(double[] array, double target)
	{
		if (array == null || array.Length == 0)
		{
			return -1;
		}
		if (array.Length == 1)
		{
			return 0;
		}
		int num = 0;
		int num2 = array.Length - 1;
		if (array[0] < array[array.Length - 1])
		{
			if (target < array[0])
			{
				return 0;
			}
			if (target > array[array.Length - 1])
			{
				return array.Length - 1;
			}
			while (num <= num2)
			{
				int num3 = (num + num2) / 2;
				if (target > array[num3])
				{
					num = num3 + 1;
				}
				if (target < array[num3])
				{
					num2 = num3 - 1;
				}
				if (target.Equals(array[num3]))
				{
					return num3;
				}
			}
			if (num < 1)
			{
				return num;
			}
			if (!(target - array[num - 1] > array[num] - target))
			{
				return num - 1;
			}
			return num;
		}
		if (target > array[0])
		{
			return 0;
		}
		if (target < array[array.Length - 1])
		{
			return array.Length - 1;
		}
		while (num <= num2)
		{
			int num4 = (num + num2) / 2;
			if (target < array[num4])
			{
				num = num4 + 1;
			}
			if (target > array[num4])
			{
				num2 = num4 - 1;
			}
			if (target.Equals(array[num4]))
			{
				return num4;
			}
		}
		if (num < 1)
		{
			return num;
		}
		if (!(target - array[num - 1] < array[num] - target))
		{
			return num - 1;
		}
		return num;
	}

	public static int BinarySearchNearIndex<T>(float[] array, double target)
	{
		if (array == null || array.Length == 0)
		{
			return -1;
		}
		if (array.Length == 1)
		{
			return 0;
		}
		int num = 0;
		int num2 = array.Length - 1;
		if (array[0] < array[array.Length - 1])
		{
			if (target < (double)array[0])
			{
				return 0;
			}
			if (target > (double)array[array.Length - 1])
			{
				return array.Length - 1;
			}
			while (num <= num2)
			{
				int num3 = (num + num2) / 2;
				if (target > (double)array[num3])
				{
					num = num3 + 1;
				}
				if (target < (double)array[num3])
				{
					num2 = num3 - 1;
				}
				if (target.Equals(array[num3]))
				{
					return num3;
				}
			}
			if (num < 1)
			{
				return num;
			}
			if (!(target - (double)array[num - 1] > (double)array[num] - target))
			{
				return num - 1;
			}
			return num;
		}
		if (target > (double)array[0])
		{
			return 0;
		}
		if (target < (double)array[array.Length - 1])
		{
			return array.Length - 1;
		}
		while (num <= num2)
		{
			int num4 = (num + num2) / 2;
			if (target < (double)array[num4])
			{
				num = num4 + 1;
			}
			if (target > (double)array[num4])
			{
				num2 = num4 - 1;
			}
			if (target.Equals(array[num4]))
			{
				return num4;
			}
		}
		if (num < 1)
		{
			return num;
		}
		if (!(target - (double)array[num - 1] < (double)array[num] - target))
		{
			return num - 1;
		}
		return num;
	}

	public static int BinarySearchNearIndex<T>(int[] array, double target)
	{
		if (array == null || array.Length == 0)
		{
			return -1;
		}
		if (array.Length == 1)
		{
			return 0;
		}
		int num = 0;
		int num2 = array.Length - 1;
		if (array[0] < array[array.Length - 1])
		{
			if (target < (double)array[0])
			{
				return 0;
			}
			if (target > (double)array[array.Length - 1])
			{
				return array.Length - 1;
			}
			while (num <= num2)
			{
				int num3 = (num + num2) / 2;
				if (target > (double)array[num3])
				{
					num = num3 + 1;
				}
				if (target < (double)array[num3])
				{
					num2 = num3 - 1;
				}
				if (target.Equals(array[num3]))
				{
					return num3;
				}
			}
			if (num < 1)
			{
				return num;
			}
			if (!(target - (double)array[num - 1] > (double)array[num] - target))
			{
				return num - 1;
			}
			return num;
		}
		if (target > (double)array[0])
		{
			return 0;
		}
		if (target < (double)array[array.Length - 1])
		{
			return array.Length - 1;
		}
		while (num <= num2)
		{
			int num4 = (num + num2) / 2;
			if (target < (double)array[num4])
			{
				num = num4 + 1;
			}
			if (target > (double)array[num4])
			{
				num2 = num4 - 1;
			}
			if (target.Equals(array[num4]))
			{
				return num4;
			}
		}
		if (num < 1)
		{
			return num;
		}
		if (!(target - (double)array[num - 1] < (double)array[num] - target))
		{
			return num - 1;
		}
		return num;
	}

	public static int BinarySearchNearIndex<T>(long[] array, double target)
	{
		if (array == null || array.Length == 0)
		{
			return -1;
		}
		if (array.Length == 1)
		{
			return 0;
		}
		int num = 0;
		int num2 = array.Length - 1;
		if (array[0] < array[array.Length - 1])
		{
			if (target < (double)array[0])
			{
				return 0;
			}
			if (target > (double)array[array.Length - 1])
			{
				return array.Length - 1;
			}
			while (num <= num2)
			{
				int num3 = (num + num2) / 2;
				if (target > (double)array[num3])
				{
					num = num3 + 1;
				}
				if (target < (double)array[num3])
				{
					num2 = num3 - 1;
				}
				if (target.Equals(array[num3]))
				{
					return num3;
				}
			}
			if (num < 1)
			{
				return num;
			}
			if (!(target - (double)array[num - 1] > (double)array[num] - target))
			{
				return num - 1;
			}
			return num;
		}
		if (target > (double)array[0])
		{
			return 0;
		}
		if (target < (double)array[array.Length - 1])
		{
			return array.Length - 1;
		}
		while (num <= num2)
		{
			int num4 = (num + num2) / 2;
			if (target < (double)array[num4])
			{
				num = num4 + 1;
			}
			if (target > (double)array[num4])
			{
				num2 = num4 - 1;
			}
			if (target.Equals(array[num4]))
			{
				return num4;
			}
		}
		if (num < 1)
		{
			return num;
		}
		if (!(target - (double)array[num - 1] < (double)array[num] - target))
		{
			return num - 1;
		}
		return num;
	}

	public static int BinarySearchNearIndex<T>(ushort[] array, double target)
	{
		if (array == null || array.Length == 0)
		{
			return -1;
		}
		if (array.Length == 1)
		{
			return 0;
		}
		int num = 0;
		int num2 = array.Length - 1;
		if (array[0] < array[array.Length - 1])
		{
			if (target < (double)(int)array[0])
			{
				return 0;
			}
			if (target > (double)(int)array[array.Length - 1])
			{
				return array.Length - 1;
			}
			while (num <= num2)
			{
				int num3 = (num + num2) / 2;
				if (target > (double)(int)array[num3])
				{
					num = num3 + 1;
				}
				if (target < (double)(int)array[num3])
				{
					num2 = num3 - 1;
				}
				if (target.Equals((int)array[num3]))
				{
					return num3;
				}
			}
			if (num < 1)
			{
				return num;
			}
			if (!(target - (double)(int)array[num - 1] > (double)(int)array[num] - target))
			{
				return num - 1;
			}
			return num;
		}
		if (target > (double)(int)array[0])
		{
			return 0;
		}
		if (target < (double)(int)array[array.Length - 1])
		{
			return array.Length - 1;
		}
		while (num <= num2)
		{
			int num4 = (num + num2) / 2;
			if (target < (double)(int)array[num4])
			{
				num = num4 + 1;
			}
			if (target > (double)(int)array[num4])
			{
				num2 = num4 - 1;
			}
			if (target.Equals((int)array[num4]))
			{
				return num4;
			}
		}
		if (num < 1)
		{
			return num;
		}
		if (!(target - (double)(int)array[num - 1] < (double)(int)array[num] - target))
		{
			return num - 1;
		}
		return num;
	}

	public static int HexToInt(string str)
	{
		return Convert.ToInt32(str, 16);
	}

	public static int BinToInt(string str)
	{
		return Convert.ToInt32(str, 2);
	}

	public static string ToBinString(this ulong value)
	{
		return ToNumberString(value, Characters.BINARY).PadLeft(64, '0').Right(64);
	}

	public static string ToBinString(this uint value)
	{
		return ToNumberString(value, Characters.BINARY).PadLeft(32, '0').Right(32);
	}

	public static string ToBinString(this ushort value)
	{
		return ToNumberString(value, Characters.BINARY).PadLeft(16, '0').Right(16);
	}

	public static string ToBinString(this byte value)
	{
		return ToNumberString(value, Characters.BINARY).PadLeft(8, '0').Right(8);
	}

	public static int RoundEx(this double value)
	{
		return (int)(value + 0.5);
	}

	public static int RoundEx(this float value)
	{
		return (int)(value + 0.5f);
	}

	public static bool EqualsFloat(this float valueA, float valueB, float eps = 1E-08f)
	{
		return Math.Abs(valueA - valueB) < eps;
	}

	public static bool EqualsDouble(this double valueA, double valueB, float eps = 1E-08f)
	{
		return Math.Abs(valueA - valueB) < (double)eps;
	}

	public static int Div(this int value, int divParam)
	{
		return value / divParam;
	}

	public static int Mod(this int value, int divParam)
	{
		return value % divParam;
	}

	public static double Rad(this double angle)
	{
		return angle * Math.PI / 180.0;
	}

	public static double Deg(this double radian)
	{
		return radian * 180.0 / Math.PI;
	}

	public static double Rad(this float angle)
	{
		return (double)angle * Math.PI / 180.0;
	}

	public static double Deg(this float radian)
	{
		return (double)radian * 180.0 / Math.PI;
	}

	public static bool IsZero(this double value)
	{
		if (value >= -5E-324)
		{
			return value <= double.Epsilon;
		}
		return false;
	}

	public static bool IsZero(this float value)
	{
		if (value >= -1E-45f)
		{
			return value <= float.Epsilon;
		}
		return false;
	}

	public static bool InRange<T>(this T value, T minValue, T maxValue) where T : IComparable
	{
		if (value == null)
		{
			throw new ArgumentNullException("value");
		}
		if (minValue.CompareTo(maxValue) == 1)
		{
			T val = minValue;
			minValue = maxValue;
			maxValue = val;
		}
		if (value.CompareTo(minValue) >= 0)
		{
			return value.CompareTo(maxValue) <= 0;
		}
		return false;
	}

	public static bool IsBetween<T>(this T t, T lowerBound, T upperBound, bool includeLowerBound = false, bool includeUpperBound = false) where T : IComparable<T>
	{
		if (t == null)
		{
			throw new ArgumentNullException("t");
		}
		int num = t.CompareTo(lowerBound);
		int num2 = t.CompareTo(upperBound);
		if ((!includeLowerBound || num != 0) && (!includeUpperBound || num2 != 0))
		{
			if (num > 0)
			{
				return num2 < 0;
			}
			return false;
		}
		return true;
	}

	public static T InRange<T>(this T value, T minValue, T maxValue, T defaultValue) where T : IComparable
	{
		if (!value.InRange(minValue, maxValue))
		{
			return defaultValue;
		}
		return value;
	}

	public static T GetLimit<T>(this T value, T lowerLimit, T upperLimit) where T : IComparable
	{
		if (lowerLimit.CompareTo(upperLimit) == 1)
		{
			T val = lowerLimit;
			lowerLimit = upperLimit;
			upperLimit = val;
		}
		if (value.CompareTo(lowerLimit) == -1)
		{
			value = lowerLimit;
		}
		if (value.CompareTo(upperLimit) == 1)
		{
			value = upperLimit;
		}
		return value;
	}

	public static T GetLowerLimit<T>(this T value, T lowerLimit) where T : IComparable
	{
		if (value.CompareTo(lowerLimit) != -1)
		{
			return value;
		}
		return lowerLimit;
	}

	public static T GetUpperLimit<T>(this T value, T upperLimit) where T : IComparable
	{
		if (value.CompareTo(upperLimit) != 1)
		{
			return value;
		}
		return upperLimit;
	}

	public static bool IsEven(this int value)
	{
		return value % 2 == 0;
	}

	public static bool IsOdd(this int value)
	{
		return value % 2 != 0;
	}

	public static bool IsEven(this long value)
	{
		return value % 2 == 0;
	}

	public static bool IsOdd(this long value)
	{
		return value % 2 != 0;
	}

	public static string ToYesNoString(this bool boolean)
	{
		if (!boolean)
		{
			return "No";
		}
		return "Yes";
	}

	public static string ToTrueFalseString(this bool boolean)
	{
		if (!boolean)
		{
			return "False";
		}
		return "True";
	}

	public static int ToInt(this bool boolean)
	{
		return boolean ? 1 : 0;
	}

	public static byte ToByte(this bool boolean)
	{
		return (byte)boolean.ToInt();
	}

	public static bool ToBool(this int value, bool Default = false)
	{
		return value switch
		{
			1 => true, 
			0 => false, 
			_ => Default, 
		};
	}

	public static bool ToBool(this byte value, bool Default = false)
	{
		return value switch
		{
			1 => true, 
			0 => false, 
			_ => Default, 
		};
	}

	internal static string Base10ToBase26(string s)
	{
		char[] array = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
		decimal num = Convert.ToDecimal(s);
		int num2 = 0;
		char[] array2 = new char[s.ToString().Length + 1];
		int num3 = 0;
		while (num >= 26m)
		{
			num2 = Convert.ToInt32(num % 26m);
			array2[num3] = array[num2];
			num = (num - (decimal)num2) / 26m;
			num3++;
		}
		array2[num3] = array[Convert.ToInt32(num)];
		string text = "";
		for (int num4 = num3; num4 >= 0; num4--)
		{
			text += array2[num4];
		}
		return text;
	}

	internal static string Base26ToBase10(string s)
	{
		string text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		System.Numerics.BigInteger bigInteger = default(System.Numerics.BigInteger);
		for (int i = 0; i <= s.Length - 1; i++)
		{
			System.Numerics.BigInteger bigInteger2 = powof(26, s.Length - i - 1);
			bigInteger += text.IndexOf(s.Substring(i, 1)) * bigInteger2;
		}
		return bigInteger.ToString();
	}

	private static System.Numerics.BigInteger powof(int x, int y)
	{
		System.Numerics.BigInteger result = 1;
		switch (y)
		{
		case 0:
			return 1;
		case 1:
			return x;
		default:
		{
			for (int i = 0; i <= y - 1; i++)
			{
				result *= (System.Numerics.BigInteger)x;
			}
			return result;
		}
		}
	}

	public static string ToNumberString(ulong number, Characters characters = Characters.DECIMAL)
	{
		return ToNumberString(number, characters.DisplayText());
	}

	public static string ToNumberString(ulong number, string customCharacter = "0123456789")
	{
		List<string> list = new List<string>();
		ulong num = number;
		if (num == 0L)
		{
			return customCharacter[0].ToString();
		}
		while (num != 0)
		{
			ulong value = num % (ulong)customCharacter.Length;
			num /= (ulong)customCharacter.Length;
			string item = customCharacter[Convert.ToInt32(value)].ToString();
			list.Insert(0, item);
		}
		return string.Join("", list.ToArray());
	}

	public static long ToNumberValue(string str, Characters characters = Characters.DECIMAL, string customCharacter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
	{
		return ToNumberValue(str, characters.DisplayText());
	}

	public static long ToNumberValue(string str, string customCharacter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
	{
		long num = 0L;
		int num2 = 0;
		string text = new string(str.ToCharArray().Reverse().ToArray());
		foreach (char value in text)
		{
			if (customCharacter.Contains(value))
			{
				num += customCharacter.IndexOf(value) * (long)Math.Pow(customCharacter.Length, num2);
				num2++;
			}
		}
		return num;
	}

	public static string ToUlidString(ulong value)
	{
		return ToNumberString(value, "0123456789ABCDEFGHJKMNPQRSTVWXYZ");
	}

	public static long ToUlidValue(string value)
	{
		return ToNumberValue(value, "0123456789ABCDEFGHJKMNPQRSTVWXYZ");
	}

	public static string ToRMBString(this decimal num)
	{
		string text = "万仟佰拾亿仟佰拾万仟佰拾元角分";
		string text2 = "";
		string text3 = "";
		int num2 = 0;
		num = Math.Round(Math.Abs(num), 2);
		string text4 = ((long)(num * 100m)).ToString();
		int length = text4.Length;
		if (length > 15)
		{
			return "溢出";
		}
		text = text.Substring(15 - length);
		for (int i = 0; i < length; i++)
		{
			string text5 = text4.Substring(i, 1);
			int startIndex = Convert.ToInt32(text5);
			string text6;
			if (i != length - 3 && i != length - 7 && i != length - 11 && i != length - 15)
			{
				if (text5 == "0")
				{
					text6 = "";
					text3 = "";
					num2++;
				}
				else if (text5 != "0" && num2 != 0)
				{
					text6 = "零" + "零壹贰叁肆伍陆柒捌玖".Substring(startIndex, 1);
					text3 = text.Substring(i, 1);
					num2 = 0;
				}
				else
				{
					text6 = "零壹贰叁肆伍陆柒捌玖".Substring(startIndex, 1);
					text3 = text.Substring(i, 1);
					num2 = 0;
				}
			}
			else if (text5 != "0" && num2 != 0)
			{
				text6 = "零" + "零壹贰叁肆伍陆柒捌玖".Substring(startIndex, 1);
				text3 = text.Substring(i, 1);
				num2 = 0;
			}
			else if (text5 != "0" && num2 == 0)
			{
				text6 = "零壹贰叁肆伍陆柒捌玖".Substring(startIndex, 1);
				text3 = text.Substring(i, 1);
				num2 = 0;
			}
			else if (text5 == "0" && num2 >= 3)
			{
				text6 = "";
				text3 = "";
				num2++;
			}
			else if (length >= 11)
			{
				text6 = "";
				num2++;
			}
			else
			{
				text6 = "";
				text3 = text.Substring(i, 1);
				num2++;
			}
			if (i == length - 11 || i == length - 3)
			{
				text3 = text.Substring(i, 1);
			}
			text2 = text2 + text6 + text3;
			if (i == length - 1 && text5 == "0")
			{
				text2 += "整";
			}
		}
		if (num == 0m)
		{
			text2 = "零元整";
		}
		return text2;
	}

	public static bool GetBit(this byte b, int index)
	{
		if (!index.InRange(0, 7))
		{
			throw new ArgumentOutOfRangeException("index");
		}
		return (b & (1 << index)) > 0;
	}

	public static byte SetBit(this byte b, int index, bool value)
	{
		if (!index.InRange(0, 7))
		{
			throw new ArgumentOutOfRangeException("index");
		}
		b = ((!value) ? ((byte)(b & ~(byte)(1 << index))) : ((byte)(b | (byte)(1 << index))));
		return b;
	}

	public static bool GetBit(this ushort b, int index)
	{
		if (!index.InRange(0, 15))
		{
			throw new ArgumentOutOfRangeException("index");
		}
		return (b & (1 << index)) > 0;
	}

	public static ushort SetBit(this ushort b, int index, bool value)
	{
		if (!index.InRange(0, 15))
		{
			throw new ArgumentOutOfRangeException("index");
		}
		b = ((!value) ? ((ushort)(b & ~(ushort)(1 << index))) : ((ushort)(b | (ushort)(1 << index))));
		return b;
	}

	public static bool GetBit(this uint b, int index)
	{
		if (!index.InRange(0, 31))
		{
			throw new ArgumentOutOfRangeException("index");
		}
		return (b & (1 << index)) > 0;
	}

	public static uint SetBit(this uint b, int index, bool value)
	{
		if (!index.InRange(0, 31))
		{
			throw new ArgumentOutOfRangeException("index");
		}
		b = ((!value) ? (b & (uint)(~(1 << index))) : (b | (uint)(1 << index)));
		return b;
	}

	public static byte ReverseBit(this byte b, int index)
	{
		b ^= (byte)(1 << index);
		return b;
	}

	public static bool IsNan(this double d)
	{
		return double.IsNaN(d);
	}

	public static bool IsNan(this float d)
	{
		return float.IsNaN(d);
	}

	public static bool IsInfinity(this double d)
	{
		return double.IsInfinity(d);
	}

	public static bool IsInfinity(this float d)
	{
		return float.IsInfinity(d);
	}

	public static bool IsNanOrInfinity(this double d)
	{
		if (!d.IsNan())
		{
			return d.IsInfinity();
		}
		return true;
	}

	public static bool IsNanOrInfinity(this float d)
	{
		if (!d.IsNan())
		{
			return d.IsInfinity();
		}
		return true;
	}

	public static bool IsIntersect(Point p1, Point p2, Point q1, Point q2)
	{
		if (Math.Max(p1.X, p2.X) < Math.Min(q1.X, q2.X))
		{
			return false;
		}
		if (Math.Min(p1.X, p2.X) > Math.Max(q1.X, q2.X))
		{
			return false;
		}
		if (Math.Max(p1.Y, p2.Y) < Math.Min(q1.Y, q2.Y))
		{
			return false;
		}
		if (Math.Min(p1.Y, p2.Y) > Math.Max(q1.Y, q2.Y))
		{
			return false;
		}
		double num = Compute(p1.X - p2.X, p1.Y - p2.Y, p1.X - q1.X, p1.Y - q1.Y);
		double num2 = Compute(p1.X - p2.X, p1.Y - p2.Y, p1.X - q2.X, p1.Y - q2.Y);
		double num3 = Compute(p1.X - q1.X, p1.Y - q1.Y, q1.X - q2.X, q1.Y - q2.Y);
		double num4 = Compute(p2.X - q1.X, p2.Y - q1.Y, q1.X - q2.X, q1.Y - q2.Y);
		if ((num * num2 < 0.0 && num3 * num4 <= 0.0) || (num * num2 <= 0.0 && num3 * num4 < 0.0))
		{
			return true;
		}
		return false;
	}

	internal static double Compute(double x1, double y1, double x2, double y2)
	{
		return x1 * y2 - y1 * x2;
	}
}
